import json
import os
import shutil
from pathlib import Path

from zeus.operation_service.app.core.asset.asset_exception import HealthCheckTaskException
from zeus.operation_service.app.core.file_util import U_RW, O_READ, G_READ
from zeus.operation_service.app.core.framework.common.result_code import RunningTaskResultCode
from zeus.operation_service.app.core.framework.task.task_result.result_generator.health_check.node_health_check_generator import \
    NodeHealthCheckGenerator
from vulcanus.log.log import LOGGER
from zeus.operation_service.app.constant import HEALTH_CHECK_PATH
from zeus.operation_service.app.core.framework.common.constant import TaskType
from zeus.operation_service.app.core.framework.task.task_factory.base_task import BaseTask
from zeus.operation_service.app.core.framework.task.task_result.result_generator.health_check.item_health_check_generator import \
    ItemHealthCheckGenerator
from zeus.operation_service.app.core.framework.task.task_result.result_generator.health_check.report_generator import ReportContext
from zeus.operation_service.app.proxy.task import TaskProxy
from zeus.operation_service.app.proxy.asset import AssetProxy
from zeus.operation_service.app.proxy.host import HostProxy
from zeus.operation_service.database import HealthCheckResultItem


class HealthCheckTask(BaseTask):

    def __init__(self, task_param):
        super().__init__(task_param)
        self.task_type = TaskType.HEALTH_CHECK

    def _post_success(self):
        LOGGER.warning(f"post_success: task name is {self.task_name}")
        report_path = os.path.join(HEALTH_CHECK_PATH, self.task_id)

        report_raw_data = self.get_health_check_report_data()
        LOGGER.warning(f"post_success: report_raw_data success")
        report_context = ReportContext()
        report_context.generator = ItemHealthCheckGenerator(report_path)
        LOGGER.warning(f"post_success: ItemHealthCheckGenerator begin")
        report_context.generate_report(report_raw_data)
        LOGGER.warning(f"post_success: ItemHealthCheckGenerator end")
        report_context.generator = NodeHealthCheckGenerator(report_path)
        LOGGER.warning(f"post_success: NodeHealthCheckGenerator begin")
        report_context.generate_report(report_raw_data)
        LOGGER.warning(f"post_success: NodeHealthCheckGenerator end")

        zip_name = f"{'_'.join(self.task_name.split('_')[:-2])}.zip"
        shutil.make_archive(report_path, "zip", report_path)
        shutil.move(f"{report_path}.zip", os.path.join(report_path, zip_name))

    def get_health_check_report_data(self):
        # 1.找到该任务用到的资产包
        # 2.找到每个资产包下巡检项的结果
        # 3.汇聚结果
        health_check_stat = dict()
        _, _, host_ids = TaskProxy().get_task_info(self.task_id)
        asset_ids, asset_items = AssetProxy().get_filtered_asset_item(self.task_id, self.task_type)
        for asset_id in asset_ids:
            asset_result = dict()
            for host_id in host_ids:
                host_result = dict()
                host = HostProxy().get_host_by_id(host_id)
                health_check_item_result = AssetProxy().get_health_check_result_item(self.task_id, host_id)
                for asset_item in asset_items:
                    health_check_item_result_filtered = health_check_item_result.filter(
                        HealthCheckResultItem.health_check_asset_item_id == asset_item.item_id)
                    if health_check_item_result_filtered.count() > 1:
                        LOGGER.error("An inspection item of a specific task contains multiple results.")
                        raise HealthCheckTaskException(RunningTaskResultCode.ERR_INVALID_TASK_RESULT_DATA)
                    if health_check_item_result_filtered.count() == 0:
                        LOGGER.error("Failed to get asset item result")
                        raise HealthCheckTaskException(RunningTaskResultCode.ERR_NO_DATA_REPORTED)

                    item_info = health_check_item_result_filtered.first()
                    host_result[asset_item.item_path] = item_info.task_result
                asset_result[f'{host.get("host_name")}@_@{host.get("host_ip")}'] = host_result
            health_check_stat[asset_id] = asset_result
        return health_check_stat

    class TaskYaml(BaseTask.TaskYaml):
        def __init__(self, task_params: dict):
            super().__init__(task_params)
            self.workflow_template = "health_check_workflow.yml"
            self.task_type = TaskType.HEALTH_CHECK

        def generate_agent_config(self, task_assets, task_case_node):
            config_json = super().generate_agent_config(task_assets, task_case_node)
            config_json = self.addition_config(config_json, task_assets, task_case_node)
            LOGGER.info(f"config json: {config_json}")
            config_json_fd = os.open(os.path.join(self.local_path, "config.json"), os.O_WRONLY | os.O_CREAT,
                                     U_RW | G_READ | O_READ)
            with os.fdopen(config_json_fd, "w") as f:
                json.dump(config_json, f)

        def addition_config(self, config_json, task_assets, task_case_node):
            return config_json

        def init_context_params(self):
            context_hosts = self.generate_host_list()
            context = {
                "hosts": context_hosts,
                "jobs": {
                    "hosts": "[" + ",".join([x["hostname"] for x in context_hosts]) + "]"
                },
                "remote_path": Path(self.remote_path).as_posix(),
                "local_path": self.local_path
            }
            return context
